/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id$
 */
package wx.xml.xalan.xalan.processor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.xml.transform.TransformerException;

import wx.xml.xalan.xalan.res.XSLMessages;
import wx.xml.xalan.xalan.res.XSLTErrorResources;
import wx.xml.xalan.xalan.templates.AVT;
import wx.xml.xalan.xalan.templates.Constants;
import wx.xml.xalan.xalan.templates.ElemTemplateElement;
import wx.xml.xalan.xml.utils.QName;
import wx.xml.xalan.xml.utils.StringToIntTable;
import wx.xml.xalan.xml.utils.StringVector;
import wx.xml.xalan.xml.utils.XML11Char;
import wx.xml.xalan.xpath.XPath;


/**
 * This class defines an attribute for an element in a XSLT stylesheet,
 * is meant to reflect the structure defined in http://www.w3.org/TR/xslt#dtd, and the
 * mapping between Xalan classes and the markup attributes in the element.
 */
public class XSLTAttributeDef {
    // How to handle invalid values for this attribute
    static final int FATAL   = 0;
    static final int ERROR   = 1;
    static final int WARNING = 2;
    /**
     * Type values that represent XSLT attribute types.
     */
    static final int T_CDATA = 1,

    // <!-- Used for the type of an attribute value that is a URI reference.-->
    T_URL = 2,

    // <!-- Used for the type of an attribute value that is an
    // attribute value template.-->
    T_AVT = 3,  // Attribute Value Template

    // <!-- Used for the type of an attribute value that is a pattern.-->
    T_PATTERN = 4,

    // <!-- Used for the type of an attribute value that is an expression.-->
    T_EXPR = 5,

    // <!-- Used for the type of an attribute value that consists
    // of a single character.-->
    T_CHAR = 6,

    // <!-- Used for the type of an attribute value that is a number. -->
    T_NUMBER = 7,

    // Used for boolean values
    T_YESNO = 8,

    // <!-- Used for the type of an attribute value that is a QName; the prefix
    // gets expanded by the XSLT processor. -->
    T_QNAME = 9,

    // <!--Used for a whitespace-separated list of QNames where the non-prefixed
    // entries are not to be placed in the default namespace. -->
    T_QNAMES = 10,

    // <!-- Used for enumerated values -->
    T_ENUM = 11,

    // Used for simple match patterns, i.e. xsl:strip-space spec.
    T_SIMPLEPATTERNLIST = 12,

    // Used for a known token.
    T_NMTOKEN = 13,

    // Used for a list of white-space delimited strings.
    T_STRINGLIST = 14,

    // Used for a list of white-space delimited strings.
    // Prefixes are checked to make sure they refer to
    // valid namespaces, and are resolved when processed
    T_PREFIX_URLLIST = 15,

    // Used for enumerated values, one of which could be a qname-but-not-ncname
    T_ENUM_OR_PQNAME = 16,

    // Used for the type of an attribute value that is a NCName
    T_NCNAME = 17,

    // Used for QName attributes that are always AVT.  Prefix isn't resolved.
    T_AVT_QNAME = 18,

    // Used for a list of QNames where non-prefixed items are to be resolved
    // using the default namespace (This is only true for cdata-section-elements)
    T_QNAMES_RESOLVE_NULL = 19,

    // Used for a list of white-space delimited strings.
    // strings are checked to make sure they are valid
    // prefixes, and are not expanded when processed.
    T_PREFIXLIST = 20;
    /**
     * Representation for an attribute in a foreign namespace.
     */
    static final XSLTAttributeDef m_foreignAttr = new XSLTAttributeDef("*", "*",
        XSLTAttributeDef.T_CDATA, false, false, WARNING);
    /**
     * Method name that objects may implement if they wish to have forein attributes set.
     */
    static final String S_FOREIGNATTR_SETTER = "setForeignAttr";
    int m_errorType = this.WARNING;
    /**
     * String that should represent the setter method which which
     * may be used on objects to set a value that represents this attribute
     */
    String m_setterString = null;
    /**
     * The allowed namespace for this element.
     */
    private String m_namespace;
    /**
     * The name of this element.
     */
    private String m_name;
    /**
     * The type of this attribute value.
     */
    private int m_type;
    /**
     * If this element is of type T_ENUM, this will contain
     * a map from the attribute string to the Xalan integer
     * value.
     */
    private StringToIntTable m_enums;
    /**
     * The default value for this attribute.
     */
    private String m_default;
    /**
     * If true, this is a required attribute.
     */
    private boolean m_required;
    /**
     * If true, this is attribute supports AVT's.
     */
    private boolean m_supportsAVT;

    /**
     * Construct an instance of XSLTAttributeDef.
     *
     * @param namespace   The Namespace URI, or an empty string.
     * @param name        The local name (without prefix), or empty string if not namespace processing.
     * @param type        One of T_CDATA, T_URL, T_AVT, T_PATTERN, T_EXPR, T_CHAR,
     *                    T_NUMBER, T_YESNO, T_QNAME, T_QNAMES, T_ENUM, T_SIMPLEPATTERNLIST,
     *                    T_NMTOKEN, T_STRINGLIST, T_PREFIX_URLLIST, T_ENUM_OR_PQNAME, T_NCNAME.
     * @param required    true if this is attribute is required by the XSLT specification.
     * @param supportsAVT true if this attribute supports AVT's.
     * @param errorType   the type of error to issue if validation fails.  One of FATAL, ERROR, WARNING.
     */
    XSLTAttributeDef(String namespace, String name, int type, boolean required, boolean supportsAVT, int errorType) {
        this.m_namespace = namespace;
        this.m_name = name;
        this.m_type = type;
        this.m_required = required;
        this.m_supportsAVT = supportsAVT;
        this.m_errorType = errorType;
    }

    /**
     * Construct an instance of XSLTAttributeDef.
     *
     * @param namespace   The Namespace URI, or an empty string.
     * @param name        The local name (without prefix), or empty string if not namespace processing.
     * @param type        One of T_CDATA, T_URL, T_AVT, T_PATTERN, T_EXPR,
     *                    T_CHAR, T_NUMBER, T_YESNO, T_QNAME, T_QNAMES, T_ENUM,
     *                    T_SIMPLEPATTERNLIST, T_NMTOKEN, T_STRINGLIST, T_PREFIX_URLLIST,
     *                    T_ENUM_OR_PQNAME, T_NCNAME.
     * @param supportsAVT true if this attribute supports AVT's.
     * @param errorType   the type of error to issue if validation fails.  One of FATAL, ERROR, WARNING.
     * @param defaultVal  The default value for this attribute.
     */
    XSLTAttributeDef(String namespace, String name, int type, boolean supportsAVT, int errorType, String defaultVal) {

        this.m_namespace = namespace;
        this.m_name = name;
        this.m_type = type;
        this.m_required = false;
        this.m_supportsAVT = supportsAVT;
        this.m_errorType = errorType;
        this.m_default = defaultVal;
    }

    /**
     * Construct an instance of XSLTAttributeDef that uses two
     * enumerated values.
     *
     * @param namespace               The Namespace URI, or an empty string.
     * @param name                    The local name (without prefix), or empty string if not namespace processing.
     * @param required                true if this attribute is required by the XSLT specification.
     * @param supportsAVT             true if this attribute supports AVT's.
     * @param prefixedQNameValAllowed If true, the type is T_ENUM_OR_PQNAME
     * @param errorType               the type of error to issue if validation fails.  One of FATAL, ERROR, WARNING.
     * @param k1                      The XSLT name of the enumerated value.
     * @param v1                      An integer representation of k1.
     * @param k2                      The XSLT name of the enumerated value.
     * @param v2                      An integer representation of k2.
     */
    XSLTAttributeDef(String namespace, String name, boolean required, boolean supportsAVT,
                     boolean prefixedQNameValAllowed, int errorType, String k1, int v1, String k2, int v2) {

        this.m_namespace = namespace;
        this.m_name = name;
        this.m_type = prefixedQNameValAllowed ? this.T_ENUM_OR_PQNAME : this.T_ENUM;
        this.m_required = required;
        this.m_supportsAVT = supportsAVT;
        this.m_errorType = errorType;
        m_enums = new StringToIntTable(2);

        m_enums.put(k1, v1);
        m_enums.put(k2, v2);
    }

    /**
     * Construct an instance of XSLTAttributeDef that uses three
     * enumerated values.
     *
     * @param namespace               The Namespace URI, or an empty string.
     * @param name                    The local name (without prefix), or empty string if not namespace processing.
     * @param required                true if this attribute is required by the XSLT specification.
     * @param supportsAVT             true if this attribute supports AVT's.
     * @param prefixedQNameValAllowed If true, the type is T_ENUM_OR_PQNAME
     * @param errorType               the type of error to issue if validation fails.  One of FATAL, ERROR, WARNING.    *
     * @param k1                      The XSLT name of the enumerated value.
     * @param v1                      An integer representation of k1.
     * @param k2                      The XSLT name of the enumerated value.
     * @param v2                      An integer representation of k2.
     * @param k3                      The XSLT name of the enumerated value.
     * @param v3                      An integer representation of k3.
     */
    XSLTAttributeDef(String namespace, String name, boolean required, boolean supportsAVT,
                     boolean prefixedQNameValAllowed, int errorType, String k1, int v1, String k2, int v2, String k3, int v3) {

        this.m_namespace = namespace;
        this.m_name = name;
        this.m_type = prefixedQNameValAllowed ? this.T_ENUM_OR_PQNAME : this.T_ENUM;
        this.m_required = required;
        this.m_supportsAVT = supportsAVT;
        this.m_errorType = errorType;
        m_enums = new StringToIntTable(3);

        m_enums.put(k1, v1);
        m_enums.put(k2, v2);
        m_enums.put(k3, v3);
    }

    /**
     * Construct an instance of XSLTAttributeDef that uses three
     * enumerated values.
     *
     * @param namespace               The Namespace URI, or an empty string.
     * @param name                    The local name (without prefix), or empty string if not namespace processing.
     * @param required                true if this attribute is required by the XSLT specification.
     * @param supportsAVT             true if this attribute supports AVT's.
     * @param prefixedQNameValAllowed If true, the type is T_ENUM_OR_PQNAME
     * @param errorType               the type of error to issue if validation fails.  One of FATAL, ERROR, WARNING.    * @param k1 The XSLT name of the enumerated value.
     * @param v1                      An integer representation of k1.
     * @param k2                      The XSLT name of the enumerated value.
     * @param v2                      An integer representation of k2.
     * @param k3                      The XSLT name of the enumerated value.
     * @param v3                      An integer representation of k3.
     * @param k4                      The XSLT name of the enumerated value.
     * @param v4                      An integer representation of k4.
     */
    XSLTAttributeDef(String namespace, String name, boolean required, boolean supportsAVT,
                     boolean prefixedQNameValAllowed, int errorType, String k1, int v1, String k2, int v2,
                     String k3, int v3, String k4, int v4) {

        this.m_namespace = namespace;
        this.m_name = name;
        this.m_type = prefixedQNameValAllowed ? this.T_ENUM_OR_PQNAME : this.T_ENUM;
        this.m_required = required;
        this.m_supportsAVT = supportsAVT;
        this.m_errorType = errorType;
        m_enums = new StringToIntTable(4);

        m_enums.put(k1, v1);
        m_enums.put(k2, v2);
        m_enums.put(k3, v3);
        m_enums.put(k4, v4);
    }

    /**
     * Get the allowed namespace for this attribute.
     *
     * @return The allowed namespace for this attribute, which may be null, or may be "*".
     */
    String getNamespace() {
        return m_namespace;
    }

    /**
     * Get the name of this attribute.
     *
     * @return non-null reference to the name of this attribute, which may be "*".
     */
    String getName() {
        return m_name;
    }

    /**
     * Get the type of this attribute value.
     *
     * @return One of T_CDATA, T_URL, T_AVT, T_PATTERN, T_EXPR, T_CHAR,
     * T_NUMBER, T_YESNO, T_QNAME, T_QNAMES, T_ENUM, T_SIMPLEPATTERNLIST,
     * T_NMTOKEN, T_STRINGLIST, T_PREFIX_URLLIST, T_ENUM_OR_PQNAME.
     */
    int getType() {
        return m_type;
    }

    /**
     * If this element is of type T_ENUM, this will return
     * a map from the attribute string to the Xalan integer
     * value.
     *
     * @param key The XSLT attribute value.
     * @return The integer representation of the enumerated value for this attribute.
     * @throws Throws NullPointerException if m_enums is null.
     */
    private int getEnum(String key) {
        return m_enums.get(key);
    }

    /**
     * If this element is of type T_ENUM, this will return
     * an array of strings - the values in the enumeration
     *
     * @return An array of the enumerated values permitted for this attribute.
     * @throws Throws NullPointerException if m_enums is null.
     */
    private String[] getEnumNames() {
        return m_enums.keys();
    }

    /**
     * Get the default value for this attribute.
     *
     * @return The default value for this attribute, or null.
     */
    String getDefault() {
        return m_default;
    }

    /**
     * Set the default value for this attribute.
     *
     * @param def String representation of the default value for this attribute.
     */
    void setDefault(String def) {
        m_default = def;
    }

    /**
     * Get whether or not this is a required attribute.
     *
     * @return true if this is a required attribute.
     */
    boolean getRequired() {
        return m_required;
    }

    /**
     * Get whether or not this attribute supports AVT's.
     *
     * @return true if this attribute supports AVT's.
     */
    boolean getSupportsAVT() {
        return m_supportsAVT;
    }

    /**
     * Get the type of error message to use if the attribute value is invalid.
     *
     * @return one of XSLAttributeDef.FATAL, XSLAttributeDef.ERROR, XSLAttributeDef.WARNING
     */
    int getErrorType() {
        return m_errorType;
    }

    /**
     * Return a string that should represent the setter method.
     * The setter method name will be created algorithmically the
     * first time this method is accessed, and then cached for return
     * by subsequent invocations of this method.
     *
     * @return String that should represent the setter method which which
     * may be used on objects to set a value that represents this attribute,
     * of null if no setter method should be called.
     */
    public String getSetterMethodName() {

        if (null == m_setterString) {
            if (m_foreignAttr == this) {
                return S_FOREIGNATTR_SETTER;
            } else if (m_name.equals("*")) {
                m_setterString = "addLiteralResultAttribute";

                return m_setterString;
            }

            StringBuffer outBuf = new StringBuffer();

            outBuf.append("set");

            if ((m_namespace != null)
                && m_namespace.equals(Constants.S_XMLNAMESPACEURI)) {
                outBuf.append("Xml");
            }

            int n = m_name.length();

            for (int i = 0; i < n; i++) {
                char c = m_name.charAt(i);

                if ('-' == c) {
                    i++;

                    c = m_name.charAt(i);
                    c = Character.toUpperCase(c);
                } else if (0 == i) {
                    c = Character.toUpperCase(c);
                }

                outBuf.append(c);
            }

            m_setterString = outBuf.toString();
        }

        return m_setterString;
    }

    /**
     * Process an attribute string of type T_AVT into
     * a AVT value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   Should be an Attribute Value Template string.
     * @return An AVT object that may be used to evaluate the Attribute Value Template.
     * @throws org.xml.sax.SAXException which will wrap a
     *                                  {@link javax.xml.transform.TransformerException}, if there is a syntax error
     *                                  in the attribute value template string.
     */
    AVT processAVT(
        StylesheetHandler handler, String uri, String name, String rawName, String value,
        ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        try {
            AVT avt = new AVT(handler, uri, name, rawName, value, owner);

            return avt;
        } catch (TransformerException te) {
            throw new org.xml.sax.SAXException(te);
        }
    }

    /**
     * Process an attribute string of type T_CDATA into
     * a String value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   non-null string reference.
     * @return The value argument.
     * @throws org.xml.sax.SAXException.
     */
    Object processCDATA(StylesheetHandler handler, String uri, String name,
                        String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {
        if (getSupportsAVT()) {
            try {
                AVT avt = new AVT(handler, uri, name, rawName, value, owner);
                return avt;
            } catch (TransformerException te) {
                throw new org.xml.sax.SAXException(te);
            }
        } else {
            return value;
        }
    }

    /**
     * Process an attribute string of type T_CHAR into
     * a Character value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   Should be a string with a length of 1.
     * @return Character object.
     * @throws org.xml.sax.SAXException if the string is not a length of 1.
     */
    Object processCHAR(
        StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {
        if (getSupportsAVT()) {
            try {
                AVT avt = new AVT(handler, uri, name, rawName, value, owner);

                // If an AVT wasn't used, validate the value
                if ((avt.isSimple()) && (value.length() != 1)) {
                    handleError(handler, XSLTErrorResources.INVALID_TCHAR, new Object[]{name, value}, null);
                    return null;
                }
                return avt;
            } catch (TransformerException te) {
                throw new org.xml.sax.SAXException(te);
            }
        } else {
            if (value.length() != 1) {
                handleError(handler, XSLTErrorResources.INVALID_TCHAR, new Object[]{name, value}, null);
                return null;
            }

            return new Character(value.charAt(0));
        }
    }

    /**
     * Process an attribute string of type T_ENUM into a int value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   non-null string that represents an enumerated value that is
     *                valid for this element.
     * @param owner
     * @return An Integer representation of the enumerated value if this attribute does not support
     * AVT.  Otherwise, and AVT is returned.
     */
    Object processENUM(StylesheetHandler handler, String uri, String name,
                       String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        AVT avt = null;
        if (getSupportsAVT()) {
            try {
                avt = new AVT(handler, uri, name, rawName, value, owner);

                // If this attribute used an avt, then we can't validate at this time.
                if (!avt.isSimple())
                    return avt;
            } catch (TransformerException te) {
                throw new org.xml.sax.SAXException(te);
            }
        }

        int retVal = this.getEnum(value);

        if (retVal == StringToIntTable.INVALID_KEY) {
            StringBuffer enumNamesList = getListOfEnums();
            handleError(handler, XSLTErrorResources.INVALID_ENUM, new Object[]{name, value, enumNamesList.toString()}, null);
            return null;
        }

        if (getSupportsAVT())
            return avt;
        else
            return new Integer(retVal);

    }

    /**
     * Process an attribute string of that is either an enumerated value or a qname-but-not-ncname.
     * Returns an AVT, if this attribute support AVT; otherwise returns int or qname.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   non-null string that represents an enumerated value that is
     *                valid for this element.
     * @param owner
     * @return AVT if attribute supports AVT. An Integer representation of the enumerated value if
     * attribute does not support AVT and an enumerated value was used.  Otherwise a qname
     * is returned.
     */
    Object processENUM_OR_PQNAME(StylesheetHandler handler, String uri, String name,
                                 String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        Object objToReturn = null;

        if (getSupportsAVT()) {
            try {
                AVT avt = new AVT(handler, uri, name, rawName, value, owner);
                if (!avt.isSimple())
                    return avt;
                else
                    objToReturn = avt;
            } catch (TransformerException te) {
                throw new org.xml.sax.SAXException(te);
            }
        }

        // An avt wasn't used.
        int key = this.getEnum(value);

        if (key != StringToIntTable.INVALID_KEY) {
            if (objToReturn == null)
                objToReturn = new Integer(key);
        }

        // enum not used.  Validate qname-but-not-ncname.
        else {
            try {
                QName qname = new QName(value, handler, true);
                if (objToReturn == null)
                    objToReturn = qname;

                if (qname.getPrefix() == null) {
                    StringBuffer enumNamesList = getListOfEnums();

                    enumNamesList.append(" <qname-but-not-ncname>");
                    handleError(handler, XSLTErrorResources.INVALID_ENUM, new Object[]{name, value, enumNamesList.toString()}, null);
                    return null;

                }
            } catch (IllegalArgumentException ie) {
                StringBuffer enumNamesList = getListOfEnums();
                enumNamesList.append(" <qname-but-not-ncname>");

                handleError(handler, XSLTErrorResources.INVALID_ENUM, new Object[]{name, value, enumNamesList.toString()}, ie);
                return null;

            } catch (RuntimeException re) {
                StringBuffer enumNamesList = getListOfEnums();
                enumNamesList.append(" <qname-but-not-ncname>");

                handleError(handler, XSLTErrorResources.INVALID_ENUM, new Object[]{name, value, enumNamesList.toString()}, re);
                return null;
            }
        }

        return objToReturn;
    }

    /**
     * Process an attribute string of type T_EXPR into
     * an XPath value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   An XSLT expression string.
     * @return an XPath object that may be used for evaluation.
     * @throws org.xml.sax.SAXException that wraps a
     *                                  {@link javax.xml.transform.TransformerException} if the expression
     *                                  string contains a syntax error.
     */
    Object processEXPR(
        StylesheetHandler handler, String uri, String name, String rawName, String value,
        ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        try {
            XPath expr = handler.createXPath(value, owner);

            return expr;
        } catch (TransformerException te) {
            throw new org.xml.sax.SAXException(te);
        }
    }

    /**
     * Process an attribute string of type T_NMTOKEN into
     * a String value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A NMTOKEN string.
     * @return the value argument or an AVT if this attribute supports AVTs.
     * @throws org.xml.sax.SAXException if the value is not a valid nmtoken
     */
    Object processNMTOKEN(StylesheetHandler handler, String uri, String name,
                          String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        if (getSupportsAVT()) {
            try {
                AVT avt = new AVT(handler, uri, name, rawName, value, owner);

                // If an AVT wasn't used, validate the value
                if ((avt.isSimple()) && (!XML11Char.isXML11ValidNmtoken(value))) {
                    handleError(handler, XSLTErrorResources.INVALID_NMTOKEN, new Object[]{name, value}, null);
                    return null;
                }
                return avt;
            } catch (TransformerException te) {
                throw new org.xml.sax.SAXException(te);
            }
        } else {
            if (!XML11Char.isXML11ValidNmtoken(value)) {
                handleError(handler, XSLTErrorResources.INVALID_NMTOKEN, new Object[]{name, value}, null);
                return null;
            }
        }
        return value;
    }

    /**
     * Process an attribute string of type T_PATTERN into
     * an XPath match pattern value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A match pattern string.
     * @return An XPath pattern that may be used to evaluate the XPath.
     * @throws org.xml.sax.SAXException that wraps a
     *                                  {@link javax.xml.transform.TransformerException} if the match pattern
     *                                  string contains a syntax error.
     */
    Object processPATTERN(
        StylesheetHandler handler, String uri, String name, String rawName, String value,
        ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        try {
            XPath pattern = handler.createMatchPatternXPath(value, owner);

            return pattern;
        } catch (TransformerException te) {
            throw new org.xml.sax.SAXException(te);
        }
    }

    /**
     * Process an attribute string of type T_NUMBER into
     * a double value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A string that can be parsed into a double value.
     * @param number
     * @return A Double object.
     * @throws org.xml.sax.SAXException that wraps a
     *                                  {@link javax.xml.transform.TransformerException}
     *                                  if the string does not contain a parsable number.
     */
    Object processNUMBER(
        StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {


        if (getSupportsAVT()) {
            Double val;
            AVT    avt = null;
            try {
                avt = new AVT(handler, uri, name, rawName, value, owner);

                // If this attribute used an avt, then we can't validate at this time.
                if (avt.isSimple()) {
                    val = Double.valueOf(value);
                }
            } catch (TransformerException te) {
                throw new org.xml.sax.SAXException(te);
            } catch (NumberFormatException nfe) {
                handleError(handler, XSLTErrorResources.INVALID_NUMBER, new Object[]{name, value}, nfe);
                return null;
            }
            return avt;

        } else {
            try {
                return Double.valueOf(value);
            } catch (NumberFormatException nfe) {
                handleError(handler, XSLTErrorResources.INVALID_NUMBER, new Object[]{name, value}, nfe);
                return null;
            }
        }
    }

    /**
     * Process an attribute string of type T_QNAME into a QName value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A string that represents a potentially prefix qualified name.
     * @param owner
     * @return A QName object if this attribute does not support AVT's.  Otherwise, an AVT
     * is returned.
     * @throws org.xml.sax.SAXException if the string contains a prefix that can not be
     *                                  resolved, or the string contains syntax that is invalid for a qualified name.
     */
    Object processQNAME(
        StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        try {
            QName qname = new QName(value, handler, true);
            return qname;
        } catch (IllegalArgumentException ie) {
            // thrown by QName constructor
            handleError(handler, XSLTErrorResources.INVALID_QNAME, new Object[]{name, value}, ie);
            return null;
        } catch (RuntimeException re) {
            // thrown by QName constructor
            handleError(handler, XSLTErrorResources.INVALID_QNAME, new Object[]{name, value}, re);
            return null;
        }
    }


    /**
     * Process an attribute string of type T_QNAME into a QName value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A string that represents a potentially prefix qualified name.
     * @param owner
     * @return An AVT is returned.
     * @throws org.xml.sax.SAXException if the string contains a prefix that can not be
     *                                  resolved, or the string contains syntax that is invalid for a qualified name.
     */
    Object processAVT_QNAME(
        StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        AVT avt = null;
        try {
            avt = new AVT(handler, uri, name, rawName, value, owner);

            // If an AVT wasn't used, validate the value
            if (avt.isSimple()) {
                int indexOfNSSep = value.indexOf(':');

                if (indexOfNSSep >= 0) {
                    String prefix = value.substring(0, indexOfNSSep);
                    if (!XML11Char.isXML11ValidNCName(prefix)) {
                        handleError(handler, XSLTErrorResources.INVALID_QNAME, new Object[]{name, value}, null);
                        return null;
                    }
                }

                String localName = (indexOfNSSep < 0)
                                   ? value : value.substring(indexOfNSSep + 1);

                if ((localName == null) || (localName.length() == 0) ||
                    (!XML11Char.isXML11ValidNCName(localName))) {
                    handleError(handler, XSLTErrorResources.INVALID_QNAME, new Object[]{name, value}, null);
                    return null;
                }
            }
        } catch (TransformerException te) {
            // thrown by AVT constructor
            throw new org.xml.sax.SAXException(te);
        }

        return avt;
    }

    /**
     * Process an attribute string of type NCName into a String
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A string that represents a potentially prefix qualified name.
     * @param owner
     * @return A String object if this attribute does not support AVT's.  Otherwise, an AVT
     * is returned.
     * @throws org.xml.sax.SAXException if the string contains a prefix that can not be
     *                                  resolved, or the string contains syntax that is invalid for a NCName.
     */
    Object processNCNAME(
        StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        if (getSupportsAVT()) {
            AVT avt = null;
            try {
                avt = new AVT(handler, uri, name, rawName, value, owner);

                // If an AVT wasn't used, validate the value
                if ((avt.isSimple()) && (!XML11Char.isXML11ValidNCName(value))) {
                    handleError(handler, XSLTErrorResources.INVALID_NCNAME, new Object[]{name, value}, null);
                    return null;
                }
                return avt;
            } catch (TransformerException te) {
                // thrown by AVT constructor
                throw new org.xml.sax.SAXException(te);
            }

        } else {
            if (!XML11Char.isXML11ValidNCName(value)) {
                handleError(handler, XSLTErrorResources.INVALID_NCNAME, new Object[]{name, value}, null);
                return null;
            }
            return value;
        }
    }

    /**
     * Process an attribute string of type T_QNAMES into a vector of QNames where
     * the specification requires that non-prefixed elements not be placed in a
     * namespace.  (See section 2.4 of XSLT 1.0.)
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A whitespace delimited list of qualified names.
     * @return a Vector of QName objects.
     * @throws org.xml.sax.SAXException if the one of the qualified name strings
     *                                  contains a prefix that can not be
     *                                  resolved, or a qualified name contains syntax that is invalid for a qualified name.
     */
    Vector processQNAMES(
        StylesheetHandler handler, String uri, String name, String rawName, String value)
        throws org.xml.sax.SAXException {

        StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f");
        int             nQNames   = tokenizer.countTokens();
        Vector          qnames    = new Vector(nQNames);

        for (int i = 0; i < nQNames; i++) {
            // Fix from Alexander Rudnev
            qnames.addElement(new QName(tokenizer.nextToken(), handler));
        }

        return qnames;
    }

    /**
     * Process an attribute string of type T_QNAMES_RESOLVE_NULL into a vector
     * of QNames where the specification requires non-prefixed elements to be
     * placed in the default namespace.  (See section 16 of XSLT 1.0; the
     * <em>only</em> time that this will get called is for the
     * <code>cdata-section-elements</code> attribute on <code>xsl:output</code>.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A whitespace delimited list of qualified names.
     * @return a Vector of QName objects.
     * @throws org.xml.sax.SAXException if the one of the qualified name strings
     *                                  contains a prefix that can not be resolved, or a qualified name contains
     *                                  syntax that is invalid for a qualified name.
     */
    final Vector processQNAMESRNU(StylesheetHandler handler, String uri,
                                  String name, String rawName, String value)
        throws org.xml.sax.SAXException {

        StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f");
        int             nQNames   = tokenizer.countTokens();
        Vector          qnames    = new Vector(nQNames);

        String defaultURI = handler.getNamespaceForPrefix("");
        for (int i = 0; i < nQNames; i++) {
            String tok = tokenizer.nextToken();
            if (tok.indexOf(':') == -1) {
                qnames.addElement(new QName(defaultURI, tok));
            } else {
                qnames.addElement(new QName(tok, handler));
            }
        }
        return qnames;
    }

    /**
     * Process an attribute string of type T_SIMPLEPATTERNLIST into
     * a vector of XPath match patterns.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A whitespace delimited list of simple match patterns.
     * @return A Vector of XPath objects.
     * @throws org.xml.sax.SAXException that wraps a
     *                                  {@link javax.xml.transform.TransformerException} if one of the match pattern
     *                                  strings contains a syntax error.
     */
    Vector processSIMPLEPATTERNLIST(
        StylesheetHandler handler, String uri, String name, String rawName, String value,
        ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        try {
            StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f");
            int             nPatterns = tokenizer.countTokens();
            Vector          patterns  = new Vector(nPatterns);

            for (int i = 0; i < nPatterns; i++) {
                XPath pattern =
                    handler.createMatchPatternXPath(tokenizer.nextToken(), owner);

                patterns.addElement(pattern);
            }

            return patterns;
        } catch (TransformerException te) {
            throw new org.xml.sax.SAXException(te);
        }
    }

    /**
     * Process an attribute string of type T_STRINGLIST into
     * a vector of XPath match patterns.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   a whitespace delimited list of string values.
     * @return A StringVector of the tokenized strings.
     */
    StringVector processSTRINGLIST(StylesheetHandler handler, String uri,
                                   String name, String rawName, String value) {

        StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f");
        int             nStrings  = tokenizer.countTokens();
        StringVector    strings   = new StringVector(nStrings);

        for (int i = 0; i < nStrings; i++) {
            strings.addElement(tokenizer.nextToken());
        }

        return strings;
    }

    /**
     * Process an attribute string of type T_URLLIST into
     * a vector of prefixes that may be resolved to URLs.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A list of whitespace delimited prefixes.
     * @return A vector of strings that may be resolved to URLs.
     * @throws org.xml.sax.SAXException if one of the prefixes can not be resolved.
     */
    StringVector processPREFIX_URLLIST(
        StylesheetHandler handler, String uri, String name, String rawName, String value)
        throws org.xml.sax.SAXException {

        StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f");
        int             nStrings  = tokenizer.countTokens();
        StringVector    strings   = new StringVector(nStrings);

        for (int i = 0; i < nStrings; i++) {
            String prefix = tokenizer.nextToken();
            String url    = handler.getNamespaceForPrefix(prefix);

            if (url != null)
                strings.addElement(url);
            else
                throw new org.xml.sax.SAXException(XSLMessages.createMessage(XSLTErrorResources.ER_CANT_RESOLVE_NSPREFIX, new Object[]{prefix}));

        }

        return strings;
    }

    /**
     * Process an attribute string of type T_PREFIXLIST into
     * a vector of prefixes that may be resolved to URLs.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A list of whitespace delimited prefixes.
     * @return A vector of strings that may be resolved to URLs.
     * @throws org.xml.sax.SAXException if one of the prefixes can not be resolved.
     */
    StringVector processPREFIX_LIST(
        StylesheetHandler handler, String uri, String name,
        String rawName, String value) throws org.xml.sax.SAXException {

        StringTokenizer tokenizer = new StringTokenizer(value, " \t\n\r\f");
        int             nStrings  = tokenizer.countTokens();
        StringVector    strings   = new StringVector(nStrings);

        for (int i = 0; i < nStrings; i++) {
            String prefix = tokenizer.nextToken();
            String url    = handler.getNamespaceForPrefix(prefix);
            if (prefix.equals(Constants.ATTRVAL_DEFAULT_PREFIX) || url != null)
                strings.addElement(prefix);
            else
                throw new org.xml.sax.SAXException(
                    XSLMessages.createMessage(
                        XSLTErrorResources.ER_CANT_RESOLVE_NSPREFIX,
                        new Object[]{prefix}));

        }

        return strings;
    }


    /**
     * Process an attribute string of type T_URL into
     * a URL value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   non-null string that conforms to the URL syntax.
     * @return The non-absolutized URL argument, in other words, the value argument.  If this
     * attribute supports AVT, an AVT is returned.
     * @throws org.xml.sax.SAXException if the URL does not conform to the URL syntax.
     */
    Object processURL(
        StylesheetHandler handler, String uri, String name, String rawName, String value, ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        if (getSupportsAVT()) {
            try {
                AVT avt = new AVT(handler, uri, name, rawName, value, owner);

                // If an AVT wasn't used, validate the value
                // if (avt.getSimpleString() != null) {
                // TODO: syntax check URL value.
                // return SystemIDResolver.getAbsoluteURI(value,
                //                                         handler.getBaseIdentifier());
                //}
                return avt;
            } catch (TransformerException te) {
                throw new org.xml.sax.SAXException(te);
            }
        } else {
            // TODO: syntax check URL value.
            // return SystemIDResolver.getAbsoluteURI(value,
            //                                         handler.getBaseIdentifier());

            return value;
        }
    }

    /**
     * Process an attribute string of type T_YESNO into
     * a Boolean value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   A string that should be "yes" or "no".
     * @return Boolean object representation of the value.
     * @throws org.xml.sax.SAXException
     */
    private Boolean processYESNO(
        StylesheetHandler handler, String uri, String name, String rawName, String value)
        throws org.xml.sax.SAXException {

        // Is this already checked somewhere else?  -sb
        if (!(value.equals("yes") || value.equals("no"))) {
            handleError(handler, XSLTErrorResources.INVALID_BOOLEAN, new Object[]{name, value}, null);
            return null;
        }

        return new Boolean(value.equals("yes") ? true : false);
    }

    /**
     * Process an attribute value.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param uri     The Namespace URI, or an empty string.
     * @param name    The local name (without prefix), or empty string if not namespace processing.
     * @param rawName The qualified name (with prefix).
     * @param value   The unprocessed string value of the attribute.
     * @return The processed Object representation of the attribute.
     * @throws org.xml.sax.SAXException if the attribute value can not be processed.
     */
    Object processValue(
        StylesheetHandler handler, String uri, String name, String rawName, String value,
        ElemTemplateElement owner)
        throws org.xml.sax.SAXException {

        int    type           = getType();
        Object processedValue = null;

        switch (type) {
            case T_AVT:
                processedValue = processAVT(handler, uri, name, rawName, value, owner);
                break;
            case T_CDATA:
                processedValue = processCDATA(handler, uri, name, rawName, value, owner);
                break;
            case T_CHAR:
                processedValue = processCHAR(handler, uri, name, rawName, value, owner);
                break;
            case T_ENUM:
                processedValue = processENUM(handler, uri, name, rawName, value, owner);
                break;
            case T_EXPR:
                processedValue = processEXPR(handler, uri, name, rawName, value, owner);
                break;
            case T_NMTOKEN:
                processedValue = processNMTOKEN(handler, uri, name, rawName, value, owner);
                break;
            case T_PATTERN:
                processedValue = processPATTERN(handler, uri, name, rawName, value, owner);
                break;
            case T_NUMBER:
                processedValue = processNUMBER(handler, uri, name, rawName, value, owner);
                break;
            case T_QNAME:
                processedValue = processQNAME(handler, uri, name, rawName, value, owner);
                break;
            case T_QNAMES:
                processedValue = processQNAMES(handler, uri, name, rawName, value);
                break;
            case T_QNAMES_RESOLVE_NULL:
                processedValue = processQNAMESRNU(handler, uri, name, rawName, value);
                break;
            case T_SIMPLEPATTERNLIST:
                processedValue = processSIMPLEPATTERNLIST(handler, uri, name, rawName,
                    value, owner);
                break;
            case T_URL:
                processedValue = processURL(handler, uri, name, rawName, value, owner);
                break;
            case T_YESNO:
                processedValue = processYESNO(handler, uri, name, rawName, value);
                break;
            case T_STRINGLIST:
                processedValue = processSTRINGLIST(handler, uri, name, rawName, value);
                break;
            case T_PREFIX_URLLIST:
                processedValue = processPREFIX_URLLIST(handler, uri, name, rawName,
                    value);
                break;
            case T_ENUM_OR_PQNAME:
                processedValue = processENUM_OR_PQNAME(handler, uri, name, rawName, value, owner);
                break;
            case T_NCNAME:
                processedValue = processNCNAME(handler, uri, name, rawName, value, owner);
                break;
            case T_AVT_QNAME:
                processedValue = processAVT_QNAME(handler, uri, name, rawName, value, owner);
                break;
            case T_PREFIXLIST:
                processedValue = processPREFIX_LIST(handler, uri, name, rawName,
                    value);
                break;

            default:
        }

        return processedValue;
    }

    /**
     * Set the default value of an attribute.
     *
     * @param handler non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param elem    The object on which the property will be set.
     * @throws org.xml.sax.SAXException wraps an invocation exception if the
     *                                  setter method can not be invoked on the object.
     */
    void setDefAttrValue(StylesheetHandler handler, ElemTemplateElement elem)
        throws org.xml.sax.SAXException {
        setAttrValue(handler, this.getNamespace(), this.getName(),
            this.getName(), this.getDefault(), elem);
    }

    /**
     * Get the primative type for the class, if there
     * is one.  If the class is a Double, for instance,
     * this will return double.class.  If the class is not one
     * of the 9 primative types, it will return the same
     * class that was passed in.
     *
     * @param obj The object which will be resolved to a primative class object if possible.
     * @return The most primative class representation possible for the object, never null.
     */
    private Class getPrimativeClass(Object obj) {

        if (obj instanceof XPath)
            return XPath.class;

        Class cl = obj.getClass();

        if (cl == Double.class) {
            cl = double.class;
        }

        if (cl == Float.class) {
            cl = float.class;
        } else if (cl == Boolean.class) {
            cl = boolean.class;
        } else if (cl == Byte.class) {
            cl = byte.class;
        } else if (cl == Character.class) {
            cl = char.class;
        } else if (cl == Short.class) {
            cl = short.class;
        } else if (cl == Integer.class) {
            cl = int.class;
        } else if (cl == Long.class) {
            cl = long.class;
        }

        return cl;
    }

    /**
     * StringBuffer containing comma delimited list of valid values for ENUM type.
     * Used to build error message.
     */
    private StringBuffer getListOfEnums() {
        StringBuffer enumNamesList = new StringBuffer();
        String[]     enumValues    = this.getEnumNames();

        for (int i = 0; i < enumValues.length; i++) {
            if (i > 0) {
                enumNamesList.append(' ');
            }
            enumNamesList.append(enumValues[i]);
        }
        return enumNamesList;
    }

    /**
     * Set a value on an attribute.
     *
     * @param handler       non-null reference to current StylesheetHandler that is constructing the Templates.
     * @param attrUri       The Namespace URI of the attribute, or an empty string.
     * @param attrLocalName The local name (without prefix), or empty string if not namespace processing.
     * @param attrRawName   The raw name of the attribute, including possible prefix.
     * @param attrValue     The attribute's value.
     * @param elem          The object that should contain a property that represents the attribute.
     * @throws org.xml.sax.SAXException
     */
    boolean setAttrValue(
        StylesheetHandler handler, String attrUri, String attrLocalName,
        String attrRawName, String attrValue, ElemTemplateElement elem)
        throws org.xml.sax.SAXException {
        if (attrRawName.equals("xmlns") || attrRawName.startsWith("xmlns:"))
            return true;

        String setterString = getSetterMethodName();

        // If this is null, then it is a foreign namespace and we
        // do not process it.
        if (null != setterString) {
            try {
                Method   meth;
                Object[] args;

                if (setterString.equals(S_FOREIGNATTR_SETTER)) {
                    // workaround for possible crimson bug
                    if (attrUri == null)
                        attrUri = "";
                    // First try to match with the primative value.
                    Class sclass = attrUri.getClass();
                    Class[] argTypes = new Class[]{sclass, sclass,
                        sclass, sclass};

                    meth = elem.getClass().getMethod(setterString, argTypes);

                    args = new Object[]{attrUri, attrLocalName,
                        attrRawName, attrValue};
                } else {
                    Object value = processValue(handler, attrUri, attrLocalName,
                        attrRawName, attrValue, elem);
                    // If a warning was issued because the value for this attribute was
                    // invalid, then the value will be null.  Just return
                    if (null == value)
                        return false;

                    // First try to match with the primative value.
                    Class[] argTypes = new Class[]{getPrimativeClass(value)};

                    try {
                        meth = elem.getClass().getMethod(setterString, argTypes);
                    } catch (NoSuchMethodException nsme) {
                        Class cl = ((Object) value).getClass();

                        // If this doesn't work, try it with the non-primative value;
                        argTypes[0] = cl;
                        meth = elem.getClass().getMethod(setterString, argTypes);
                    }

                    args = new Object[]{value};
                }

                meth.invoke(elem, args);
            } catch (NoSuchMethodException nsme) {
                if (!setterString.equals(S_FOREIGNATTR_SETTER)) {
                    handler.error(XSLTErrorResources.ER_FAILED_CALLING_METHOD, new Object[]{setterString}, nsme);//"Failed calling " + setterString + " method!", nsme);
                    return false;
                }
            } catch (IllegalAccessException iae) {
                handler.error(XSLTErrorResources.ER_FAILED_CALLING_METHOD, new Object[]{setterString}, iae);//"Failed calling " + setterString + " method!", iae);
                return false;
            } catch (InvocationTargetException nsme) {
                handleError(handler, XSLTErrorResources.WG_ILLEGAL_ATTRIBUTE_VALUE,
                    new Object[]{Constants.ATTRNAME_NAME, getName()}, nsme);
                return false;
            }
        }

        return true;
    }

    private void handleError(StylesheetHandler handler, String msg, Object[] args, Exception exc) throws org.xml.sax.SAXException {
        switch (getErrorType()) {
            case (FATAL):
            case (ERROR):
                handler.error(msg, args, exc);
                break;
            case (WARNING):
                handler.warn(msg, args);
            default:
                break;
        }
    }
}
